/**
 * @file ThreadLock.cpp
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2025-05-30
 * 
 *  生产者消费者模型
 *  当队列为空时，消费者线程必须等待，直到有新的任务加入
 *  当队列已满时。生产者必须等待，直到有空间可用
 *  最简单的方法是忙等待，或者自旋转
 * 
 * std::condition_variable 
 * std::condition_variable 提供了一种机制，允许一个或多个线程阻塞（等待），
 * 直到收到另一个线程发出的通知（notify），并且某个特定的条件得到满足
 * （1） wait(): 调用此函数的线程会被阻塞，直到被通知唤醒
 * wait() 操作必须与一个互斥锁（std::mutex）关联使用。这个互斥锁用于保护那个需要检查的“条件”（例如，队列是否为空的状态）
 *（2）notify_one(): 唤醒一个正在等待（调用 wait()）的线程。如果有多个线程在等待，系统会选择其中一个唤醒
 * （3）notify_all(): 唤醒所有正在等待的线程
 * 
 * 
 */

#include <iostream>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <queue>
using namespace std;

typedef struct Job
{
    int id;
    Job(int ids){id=ids;}
}Job;


mutex mtx;
condition_variable cv;
bool ready = false;   //表示数据是否已经生成

bool finished = false;
std::queue<Job> que;
const static int counts = 5;

void produce_thread(int id)
{
    for (int i = 0; i < counts; i++)
    {
        this_thread::sleep_for(std::chrono::seconds(1));
        std::lock_guard<std::mutex> lock(mtx);
        que.emplace(Job(i));
        cout<<"Prodecer thread "<<id<<" produce job " <<i<<" que size:"<<que.size()<<endl;
        cv.notify_one();
    }
    
}

void consume_thread(int id)
{
    while (true)
    {
        std::unique_lock<std::mutex> lock(mtx);
        cout<<"consume_thread waitting, que size:"<<que.size()<<" finished:"<<finished<<endl;
        cv.wait(lock, []{return !que.empty() || finished;});
        while (!que.empty())
        {
            Job job = que.front();
            que.pop();
            cout<<"consumer thread "<<id<<" consume data "<<job.id<<" que size:"<<que.size()<<endl;
            std::this_thread::sleep_for(std::chrono::seconds(1));
        }
        if (finished && que.empty()) break;
        
    }
    
}

void produce()
{
    std::this_thread::sleep_for(std::chrono::seconds(2)); 
    std::lock_guard<std::mutex>lock(mtx);
    ready = true;     // 数据生成
    cv.notify_one();  // 通知消费者
}

void consume()
{
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{return ready;});   //等待数据生成
    std::cout<<"consumer thread"<<endl;

    std::this_thread::sleep_for(std::chrono::seconds(2));
    cout<<"conume finish"<<endl;
}


int main()
{
    // std::thread t1(produce);
    // std::thread t2(consume);
    // t1.join();
    // t2.join();
    const int thread_nums = 1;
    std::thread producers[thread_nums];
    std::thread consumers[thread_nums];
    for(int i  =0 ; i < thread_nums; i++){
        producers[i] = std::thread(produce_thread, i);
        consumers[i] = std::thread(consume_thread, i);
    }
    for(auto&it : producers){
        it.join();
    }
    //主线程会阻塞等待到produces线程完成
    cout<<"produce finish"<<endl;
    finished = true;
    //cv.notify_all();
    for(auto&it:consumers){
        it.join();
    }
    cout<<"consume finish"<<endl;
}